/***
 * * PROJECT
 * *    ATaG
 * * VERSION
 * *    $Revision: 1.27 $
 * * DATE
 * *    $Date: 2008/10/07 12:57:36 $
 * * LOG
 * *    $Log: Main.java,v $
 * *    Revision 1.27  2008/10/07 12:57:36  animesh
 * *    removed GPL License [will re-add to all files later]
 * *
 * *    Revision 1.26  2007/11/20 22:44:56  animesh
 * *    no message
 * *
 * *    Revision 1.25  2007/08/18 07:02:34  animesh
 * *    generates actual code bundles now
 * *
 * *    Revision 1.24  2007/08/17 20:38:14  animesh
 * *    added CreateDataItemUtils code
 * *
 * *    Revision 1.23  2007/08/17 08:13:51  animesh
 * *    Node Specific code half done.
 * *
 * *    Revision 1.22  2007/08/08 18:30:04  animesh
 * *    ATaGManager generation half done.
 * *
 * *    Revision 1.21  2007/07/27 19:48:23  animesh
 * *    code generation added
 * *
 * *    Revision 1.20  2007/06/01 20:52:31  animesh
 * *    bulk update.
 * *
 * *    Revision 1.19  2007/03/16 18:05:50  animesh
 * *    Moved file generation functions to ImperativeCodeGenerator
 * *
 * *    Revision 1.18  2007/02/02 11:23:58  lmottola
 * *    Benchmarking code for compiler in.
 * *
 * *    Revision 1.17  2007/01/29 20:07:18  animesh
 * *    changed the check of "is task already assigned" from t.assignedTo() == null to t.assignedTo.size() == 0. The null idea does not work since the arraylist is initialized by the constructor of the abstract task.
 * *
 * *    Revision 1.16  2007/01/29 18:47:04  lmottola
 * *    Modified task assignment process.
 * *
 * *    Revision 1.15  2007/01/29 17:05:41  animesh
 * *    commented out the exception thrown in main, since implementation is done now.
 * *
 * *    Revision 1.14  2007/01/28 21:40:25  animesh
 * *    changed network file base.
 * *
 * *    Revision 1.13  2007/01/15 09:20:26  animesh
 * *    fixed typo addEgde to addEdge :-).
 * *
 * *    Revision 1.12  2007/01/15 09:15:35  animesh
 * *    added function to add edges. Not working as of now.
 * *
 * *    Revision 1.11  2007/01/15 09:13:46  animesh
 * *    added function to add edges. Not working as of now.
 * *
 * *    Revision 1.10  2007/01/05 09:31:46  lmottola
 * *    Modified constructor in NetworkTopology.
 * *
 * *    Revision 1.9  2006/12/30 09:39:26  animesh
 * *    restructured the code a bit. Added a 2-pass task allocator. current strategies are naive, but designed to "just work".
 * *
 * *    Revision 1.8  2006/12/14 05:15:16  lmottola
 * *    Moved Estimator in atag.compiler and various cleanup.
 * *
 * *    Revision 1.7  2006/12/05 00:10:31  animesh
 * *    added dummy call to estimator.
 * *
 * *    Revision 1.6  2006/10/25 22:32:55  animesh
 * *    changed ATaGChannelDeclaration to ScopedChannel
 * *
 * *    Revision 1.5  2006/10/19 23:36:27  animesh
 * *    *** empty log message ***
 * *
 * *    Revision 1.3  2006/10/19 21:21:53  lmottola
 * *    Added CVS preamble.
 * *
 * *
 * *   ATaG (Abstract Task Graph) - Data-driven Macroprogramming for
 * *                                Sensor Networks
 * *
 ***/

package atag.compiler;

import atag.runtime.ln.nodeAttributes.SetAttribute;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import java.util.Vector;

import atag.common.ATaGDataItemDeclaration;
import atag.common.ATaGProgram;
import atag.common.ATaGTaskDeclaration;
import atag.common.NetworkTopology;
import atag.common.ScopedChannel;
import atag.runtime.NodeInfo;
import atag.runtime.ln.LNScope;
import atag.runtime.ln.estimation.LNSimpleEstimator;
import atag.runtime.ln.estimation.LNStaticHelper;
import atag.runtime.ln.nodeAttributes.NodeAttribute;

/**
 *
 * @author Animesh
 */
public class Main {
    
    /**
     * constants to represent file paths can maybe replaced with arguments that
     * are passed when the program runs
     */
    
    private static String absoluteBase = ".";
    
    //private static String dartRoot = absoluteBase + "\\DART-java\\atag";
    
    private static String autoGenAppDir = absoluteBase
            + "\\AutoGenerated\\Application";
    
    private static String autoGenRoot = absoluteBase + "\\AutoGenerated";
    
    private static String configFileDestDir = absoluteBase + "\\config";
    
    // private static String networkFileBase = absoluteBase +
    // "\\AutoGenerated\\Network\\";
    private static String networkFileBase = absoluteBase + "\\network\\";
    
    private static String runNodesBatchFilePath = absoluteBase
            + "\\DART-class\\runNodes.bat";
    
    private static String runGUIBatchFilePath = absoluteBase
            + "\\GUI-class\\runGUI.bat";
    
    // TODO - get these parameters as inputs
    private static String codeBaseDirPath = "";
    private static String deploymentBaseDirPath = "";
    
    
    /** Creates a new instance of Main */
    public Main() {
    }
    
    /**
     * @param args
     *            the command line arguments Essentially take the filename from
     *            command prompt and feed to the parser class. Then generate all
     *            the files.
     */
    public static void main(String[] args,ATaGProgram atag_p) {
        
        boolean configFileFlag = false;
        boolean codeTemplateFlag = false;
        
        int randomSeed;
        
        byte optimizationFlag = 0x0;
        
         if (args.length != 6)
        {
            System.err.println("Usage: java appname atagfilename topologyfilename "
                    + "templateonly|configonly|templateandconfig "
                    + "random|sticky|centroid randomSeed dartRoot");
            System.exit(1);
        }
        
       //ATaGProgram aProgram = ATaGParser.parseATaGProgram(args[0]);
        ATaGProgram atg_program = atag_p;
        atg_program.sanitize();
        
        // read the topology file into a Network Topology
        NetworkTopology nTopo = new NetworkTopology();        
        // possibly parse the args and set paths
        // TODO
        
        // set task flags
        if (args[2].equalsIgnoreCase("templateonly")) {
            codeTemplateFlag=true;
        } else if (args[2].equalsIgnoreCase("configonly")) {
            nTopo.readTopologyFile(args[1]);        
            configFileFlag = true;
        } else if (args[2].equalsIgnoreCase("templateandconfig")) {
            nTopo.readTopologyFile(args[1]);
            configFileFlag = true;
            codeTemplateFlag=true;
        } else {
            System.out.println("Invalid task " + args[2] + " supplied");
            System.exit(-8);
        }
         
                
        // set compilation flags
        if (args[3].equalsIgnoreCase("random")) {
            optimizationFlag = 0x1;
        } else if (args[3].equalsIgnoreCase("sticky")) {
            optimizationFlag = 0x2;
        } else if (args[3].equalsIgnoreCase("centroid")) {
            optimizationFlag = 0x4;
        } else {
            System.out.println("Invalid optimization technique " + args[3] + " supplied");
            System.exit(-8);
        }
        
        randomSeed = Integer.parseInt(args[4]);
        
        String dartRoot = args[5];
        //String dartRoot = "/home/mahanth/aug21SN";
        
        // Create a function to generate the code given the ATaGProgram Object
        // Animesh says -- how about we break this into the stages as
        // defined in the block diagram?
        // generateFiles(aProgram,nTopo,codeTemplateFlag, configFileFlag);
        compileProgram(atg_program, nTopo, codeTemplateFlag, configFileFlag,
                optimizationFlag, randomSeed, dartRoot);
        
    }
    
    /**
     * Create the code templates
     * @param aProgram
     *            The ATaG Program to be converted into code
     * @returns false if a component fails. true otherwise
     */
    
    private static boolean createCodeTemplates(ATaGProgram aProgram, String dartRoot) {
    	
    	System.out.println("Creating code templates in: "+ dartRoot);
        
        if (!ImperativeCodeGenerator.CreateAppDir(aProgram, dartRoot)) {
            System.err.println("App Dir creation failed");
            return false;
        }
        if (!ImperativeCodeGenerator.CreateIDConstants(aProgram, dartRoot)) {
            System.err.println("Code [ID] template generation failed");
            return false;
        }
        if (!ImperativeCodeGenerator.CreateDataItemUtils(aProgram, dartRoot)) {
            System.err.println("Code [DataItemUtils] template generation failed");
            return false;
        }
        if (!ImperativeCodeGenerator.CreateTaskTemplates(aProgram, dartRoot)) {
            System.err.println("Code [Task] template generation failed");
            return false;
        }
        if (!ImperativeCodeGenerator.CreateDataTemplates(aProgram, dartRoot)) {
            System.err.println("Code [Data] template generation failed");
            return false;
        }
        if (!ImperativeCodeGenerator.CreateATaGManager(aProgram, dartRoot)) {
            System.err.println("Code [ATaGManager] template generation failed");
            return false;
        }
        return true;
    }
    
    /**
     * The function that generates the config files
     * @deprecated
     *
     * @param aProgram
     *            The ATaG Program to be compiled
     * @param nTopo
     *            The Target Network Topology.
     */
    
    private static void GenerateConfigFiles(ATaGProgram aProgram,
            NetworkTopology nTopo) {
        String[] configStrings;
        configStrings = new String[nTopo.getNumberOfNodes()];
        for (int i = 0; i < nTopo.getNumberOfNodes(); i++) {
            configStrings[i] = "-myID " + i + " ";
            configStrings[i] += "-ndata " + aProgram.numDataItems()
            + " -ntasks " +
                    // Animesh says - why are the hop and distance scopes zero??
                    aProgram.numTasks() + " " + "-hopscope 0 -distancescope 0 ";
            configStrings[i] += "-assignedtasks ";
        }
        
        // go through all tasks and assign them to the suitable nodes
        // parse only two types (all nodes or one on id) for now; add rest later
        for (ATaGTaskDeclaration t : aProgram.getTaskList()) {
            
            int assignedNodes[] = assignTaskToNodes(t, nTopo);
            // for each node to which the task is assigned
            for (int j = 0; j < assignedNodes.length; j++) {
                t.assign(assignedNodes[j]);
                configStrings[j] += t.getID() + " ";
            }// for each node to which the task is assigned
            
                        /*
                         * int instType = t.getLocation()[0]; int instParam =
                         * t.getLocation()[1]; if ((instType ==
                         * ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE) &&
                         * (instParam == 1)) for (int j=0; j < nTopo.getNumberOfNodes();
                         * j++) { t.assign(j); configStrings[j] += t.getID() + " "; } else
                         * if (instType == ATaGTaskDeclaration.INSTANTIATION_ONE_ON_NODE_ID) {
                         * t.assign(instParam); configStrings[instParam] += t.getID() + " "; }
                         */
        }
        
        // now add senddata (assignments are part of taskInfo now)
        for (int i = 0; i < aProgram.numDataItems(); i++) {
            ATaGDataItemDeclaration d = aProgram.getDataList().get(i);
            // now get input channels for this data
            
            ScopedChannel[] inChannels = aProgram.inputChannelsD(d.getID());
            ScopedChannel[] outChannels = aProgram.outputChannelsD(d.getID());
            int[] producerMap = null;
            Set<Integer> consumerMap = new HashSet<Integer>();
            
            // who are the producer tasks? (should be ONLY one!)
            for (int j = 0; j < outChannels.length; j++) {
                ATaGTaskDeclaration producer = aProgram.getTaskList().get(
                        outChannels[j].getTaskID());
                // where is this mapped?
                producerMap = producer.assignment();
            }
            
            // if there are no consumers, do nothing
            if (inChannels.length == 0)
                continue; // look at next data item
            // else, find out if any consumer has all-nodes input interest
            for (int j = 0; j < inChannels.length; j++)
                if ((inChannels[j].getInterest().toUpperCase())
                .equals("ALL-NODES")) {
                // who is the consumer?
                ATaGTaskDeclaration consumer = aProgram.getTaskList().get(
                        inChannels[j].getTaskID());
                // where is it mapped?
                int[] destinations = consumer.assignment();
                // store the list in the consumerMap set
                for (int k = 0; k < destinations.length; k++)
                    consumerMap.add(new Integer(destinations[k]));
                }
            // now the set contains all non-duplicate nodes that are the
            // destination
            // for each of the producer nodes, create the -senddata for this
            // data id
            if (consumerMap.size() > 0) {
                for (int j = 0; j < producerMap.length; j++) {
                    configStrings[producerMap[j]] += "-senddata " + d.getID()
                    + " ";
                    Iterator it = consumerMap.iterator();
                    while (it.hasNext()) {
                        configStrings[producerMap[j]] += ((Integer) it.next())
                        .intValue()
                        + " ";
                    }
                }
            }
        }
        
        // finish and write to file
        for (int i = 0; i < nTopo.getNumberOfNodes(); i++) {
            
            configStrings[i] += "-end";
            try {
                BufferedWriter configFile = new BufferedWriter(new FileWriter(
                        configFileDestDir + "\\config" + i + ".txt"));
                configFile.write(configStrings[i]);
                configFile.close();
            } catch (IOException ex) {
                System.out.println("Could not create the config files");
                System.out.println(ex.getMessage());
                ex.printStackTrace();
            }
        }
    }
    
    /**
     *
     * @deprecated
     * @param aProgram
     *            the ATaG Program
     * @param nTopo
     *            the Network Topology Generates all the files needed
     */
    private static void generateFiles(ATaGProgram aProgram,
            NetworkTopology nTopo, boolean codeTemplateFlag,
            boolean configFileFlag, String dartRoot) {
        
        String fileName = nTopo.getName(); // 20node? -- get from
        // NetworkTopology?
        String topoFileName = networkFileBase + fileName;
        
        if (codeTemplateFlag) {
            if (!createCodeTemplates(aProgram, dartRoot))
                return;
            // check if shortcut .url exists to compile script
            // create shortcut to the simulation script .bat file here
                        /*
                         * we will not make a shortcut to the BAT file if (!(new
                         * File("C:\\Documents and
                         * Settings\\Amol\\Desktop\\CompileDART.url")).exists()) { try {
                         * BufferedWriter compileShort = new BufferedWriter(new FileWriter(
                         * "C:\\Documents and Settings\\Amol\\Desktop\\CompileDART.url"));
                         * compileShort.write(
                         * "[InternetShortcut]\nURL=file://C:/ATaG-Demo/compileDART.bat");
                         * compileShort.close(); } catch (IOException ex) {
                         * ex.printStackTrace(); }
                         */
        }// if codeTemplateFlag
        
        // check configFileFlag
        
        if (!configFileFlag)
            return;
                /*
                 * -- assuming we "have" to overwrite files in config dir. while
                 * (confirmOverwriteFlag == false) { configFileDestDir =
                 * Helper.getFileName(true, "Select directory for config file(s)",
                 * "C:\\ATaG-Demo\\config", "Generate config file(s) here", null);
                 * Object[] options4 = {"Overwrite and proceed", "Select another
                 * directory", "Abort"}; answer = JOptionPane.showOptionDialog(null,
                 * "Existing contents of this directory will be overwritten.", "Step 4",
                 * JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null,
                 * options4, options4[0]);
                 *
                 * if (answer == JOptionPane.CANCEL_OPTION) return; else if (answer ==
                 * JOptionPane.YES_OPTION) confirmOverwriteFlag = true; }
                 */
        System.out.println("Clearing all files from " + configFileDestDir
                + " and generating new ones");
        
        if (!Helper.deleteAllFilesInDir(new File(configFileDestDir))) {
            System.err
                    .println("Could not overwrite existing contents. Exiting.");
            return;
        }
        
        GenerateConfigFiles(aProgram, nTopo);
        
        // C:\ATaG-Demo\compileDART.bat remains unchanged; write it anyway if it
        // doesnt exist
        // Check if shortcut on Desktop exists
        
        // generate C:\ATaG-Demo\DART-class\runNodes.bat simulation script (in
        // the default path)
        // use configFileDestDir as the absolute path and suffix with individual
        // node ID config file
        // start /b java atag.runtime.Startup -network c:/network20.txt
        // -config <configFileDestDir>/config0.txt
        String runNodesStr = "";
        for (int i = 0; i < nTopo.getNumberOfNodes(); i++) {
            runNodesStr += "start /b java -classpath " + absoluteBase
                    + "\\DART-class atag.runtime.Startup -network ";
            runNodesStr += topoFileName;
            runNodesStr += "-config " + configFileDestDir + "\\config" + i
                    + ".txt\n";
        }
        try {
            BufferedWriter runNodes = new BufferedWriter(new FileWriter(
                    runNodesBatchFilePath));
            runNodes.write(runNodesStr);
            runNodes.close();
        } catch (IOException ex) {
            System.err.println("Could not write the runNodes Batch file at "
                    + runNodesBatchFilePath);
        }
        
                /*
                 * // create shortcut to the simulation script .bat file here if (!(new
                 * File("C:\\Documents and
                 * Settings\\Amol\\Desktop\\StartSimulation.url")).exists()) { try {
                 * BufferedWriter batShort = new BufferedWriter(new FileWriter(
                 * "C:\\Documents and Settings\\Amol\\Desktop\\StartSimulation.url"));
                 * batShort.write(
                 * "[InternetShortcut]\nURL=file://C:/ATaG-Demo/DART-class/runNodes.bat");
                 * batShort.close(); } catch (IOException ex) { } }
                 *
                 */
        
        // create runGUI.bat file here
        // start /b java visualizer.Startup
        try {
            BufferedWriter guiStart = new BufferedWriter(new FileWriter(
                    runGUIBatchFilePath));
            guiStart.write("start /b java visualizer.Startup " + topoFileName);
            guiStart.close();
        } catch (IOException ex) {
        }
        
                /*
                 * no shortcut for now...
                 *  // create shortcut to the visualization launch .bat file here if
                 * (!(new File("C:\\Documents and
                 * Settings\\Amol\\Desktop\\LaunchGUI.url")).exists()) { try {
                 * BufferedWriter batShort = new BufferedWriter(new FileWriter(
                 * "C:\\Documents and Settings\\Amol\\Desktop\\LaunchGUI.url"));
                 * batShort.write(
                 * "[InternetShortcut]\nURL=file://C:/ATaG-Demo/GUI-class/runGUI.bat");
                 * batShort.close(); } catch (IOException ex) { } }
                 */
    }
    
    
    /**
     * The mother of all functions. The function that decides what code goes on
     * what node.
     *
     * @deprecated
     * @param t
     *            The ATaG Task to be mapped
     * @param nTopo
     *            The Target Network Topology.
     * @returns the list of nodes on which this task should be assinged
     */
    private static int[] assignTaskToNodes(ATaGTaskDeclaration t,
            NetworkTopology nTopo) {
        int[] nodesAssigned = new int[0];
        
        int instType = t.getLocation()[0];
        int instParam = t.getLocation()[1];
        
        switch (instType) {
            case ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE:
                if (instParam == 1) {
                    nodesAssigned = new int[nTopo.getNumberOfNodes()];
                    for (int j = 0; j < nTopo.getNumberOfNodes(); j++) {
                        nodesAssigned[j] = j;
                    }
                } else {
                    // currently dies.. replace with code that handles other values
                    // later
                    System.err.println("Illegal instantiation parameter "
                            + instParam + " for task" + t.getName()
                            + "with instantiation type nodes-per-instance");
                    System.exit(-5);
                }
                break;
            case ATaGTaskDeclaration.INSTANTIATION_ONE_ON_NODE_ID:
                nodesAssigned = new int[1];
                nodesAssigned[0] = instParam;
                break;
            case ATaGTaskDeclaration.INSTANTIATION_ONE_ANYWHERE:
                nodesAssigned = new int[1];
                int destinationNode;
                // completely random assignment -- random selects a number in [0,1)
                destinationNode = (int) (Math.random() * nTopo.getNumberOfNodes());
                nodesAssigned[0] = destinationNode;
                break;
            case ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE_FRACTIONAL:
                // do nothing.. allow this to run into default. Fix later
            default:
                System.err.println("Illegal instantiation type " + t.getInstType()
                + " for task" + t.getName());
                System.exit(-5);
        }
        return nodesAssigned;
    }
    
    private double[] EnergyEstimate(NetworkTopology nTopo) {
        int dummyID = 0;
        LNScope[] destinationScopes = new LNScope[2];
        
        Estimator m_Estimator = new DummyEstimator(nTopo);
        
        ArrayList communications = new ArrayList();
        Vector newElement = new Vector();
        newElement.add(new Integer(dummyID));
        newElement.add(destinationScopes);
        
        return m_Estimator.getCostEstimate(communications);
    }
    
    
    /**
     * Compiles the program.
     *
     */
    private static void compileProgram(ATaGProgram aProgram,
            NetworkTopology nTopo, boolean codeTemplateFlag,
            boolean configFileFlag, byte optimizationFlag, int randomSeed,
            String dartRoot) {
        System.out.println("configflag="+configFileFlag);
        // first.. generate the Task and DataItem Templates, if needed
        // [remember to print a message for the user when the files are created]
        if (codeTemplateFlag){
            createCodeTemplates(aProgram, dartRoot);
        }
        
        
        
        // then, if needed, Generate an ITaG from an ATaG
        if(configFileFlag){
            ITaGProgram equivITaG = new ITaGProgram(aProgram, nTopo);
            
            ComposedATaG caProgram = new ComposedATaG(aProgram);
            
            
            
            //the line below will later get a switch/case when we have many task assigners
            TaskAssigner tAssigner = null;
            switch(optimizationFlag){
                case 0x01:
                    tAssigner = new RandomTaskAssigner();
                    break;
                case 0x02:
                    tAssigner = new StickyTaskAssigner();
                    break;
                case 0x04:
                    tAssigner = new CentroidTaskAssigner();
                    break;
                default:
                    System.err.println("Invalid optimization flag ID " + optimizationFlag);
                    System.exit(-8);
            }
            
            
            tAssigner.assignTasks(aProgram, equivITaG, caProgram, nTopo, randomSeed);
            
            LNSimpleEstimator estimator = new LNSimpleEstimator(nTopo);
            
            // LNPredicate attachedActuator = new SetMembershipPredicate("RGSignal",
            // SetMembershipPredicate.IS_IN, "attachedActuators");
            // LNPredicate attachedSensor = new SetMembershipPredicate(
            // "PresenceSensor", SetMembershipPredicate.IS_IN,
            // "attachedSensors");
            // LNScope scopeActuator = new ConjunctiveScope(
            // new LNPredicate[] { attachedActuator });
            // LNScope scopeSensorActuator = new ConjunctiveScope(new LNPredicate[]
            // {
            // attachedActuator, attachedSensor });
            
            LinkedList<CommPattern> commPatterns = getCommunicationPatterns(
                    aProgram, nTopo);
            // commPatterns.add(new CommPattern(6, scopeActuator));
            // commPatterns.add(new CommPattern(0, scopeSensorActuator));
            
            double[] costEstimates = estimator.getCostEstimate(commPatterns);
            
            printCostEstimates(nTopo, costEstimates);
            
            createNodeSpecificCodes(aProgram, nTopo, dartRoot);
        }
        
    }
    
    /**
     * @param aProgram
     *            We assume that the tasks in this already know where they are
     *            assigned
     * @param nTopo
     *            We assume that the nodes in this network topology already know
     *            what nodes are assigned to them
     * @returns A linked list of communication patterns
     */
    private static LinkedList<CommPattern> getCommunicationPatterns(
            ATaGProgram aProgram, NetworkTopology nTopo) {
        LinkedList<CommPattern> retList = new LinkedList<CommPattern>();
        
        for (ATaGTaskDeclaration t : aProgram.getTaskList()) {
            if (t.getFiringRule()[0] == ATaGTaskDeclaration.FIRING_PERIODIC) {
                for (Integer assignedNodeID : t.getAssignedTo()) {
                    // for each assigned node, for each periodic task, trace
                    // till end
                    addEdge(nTopo, assignedNodeID.intValue(), aProgram, t,
                            retList);
                    // TODO this is where you can multiply the cost by the
                    // number of times
                    // the task will fire in the "sample period"
                }
            }
        }
        
        return retList;
    }
    
    private static void addEdge(NetworkTopology nTopo, int nodeID,
            ATaGProgram aProgram, ATaGTaskDeclaration t, LinkedList retList) {
        
        NodeInfo tempN = nTopo.getNodeInfoByID(nodeID);
        
        // for each data item produced by the task
        for (ATaGDataItemDeclaration d : aProgram.getOutDataListOfTask(t
                .getID())) {
            
            ArrayList<ATaGTaskDeclaration> targetTasks = aProgram
                    .getOutTasksListOfData(d.getID());
            // int numOutChannels = targetTasks.size();
            // for each task "consuming that data item"
            for (ATaGTaskDeclaration targetT : targetTasks) {
                LNScope tempScope = aProgram.getLNScopeForData(t.getID(), d
                        .getID(), tempN, targetT);
                // add that scope to the list
                retList.add(new CommPattern(nodeID, tempScope));
                // get list of nodes belonging to that scope
                LinkedList<Integer> targetNodeIDs = LNStaticHelper
                        .determineMatchingNodes(nTopo, tempScope);
                // for each such node, if it has targetT, recurse
                for (Integer tnID : targetNodeIDs) {
                    if (nTopo.getNodeInfoByID(tnID.intValue()).isTaskAssigned(
                            targetT.getID())) {
                        addEdge(nTopo, tnID.intValue(), aProgram, targetT,
                                retList);
                    }
                }
            }
        }
        return;
    }
    
    private static void printCostEstimates(NetworkTopology nTopo, double[] costEstimates) {
        int maxNodeID = -1;
        double maxNodeCost = 0;
        double totalCost = 0;
        
        for (int i = 0; i< nTopo.getNumberOfNodes(); i++){
            totalCost = totalCost + costEstimates[i];
            if (costEstimates[i] > maxNodeCost){
                maxNodeCost = costEstimates[i];
                maxNodeID = i;
            }
        }
        
        //Now do the printing
        
        System.out.println("#----" + nTopo.getNumberOfNodes() + "nodes----------------");
        System.out.println("#numNodes xrange yrange maxnodeID maxCost totalCost");
        System.out.println(nTopo.getNumberOfNodes() + " " +
                nTopo.getXRange() + " " + nTopo.getYRange() + " "
                + maxNodeID + " " + maxNodeCost + " " + totalCost);
        for (int i = 0; i< nTopo.getNumberOfNodes(); i++){
            // x y cost
            NodeInfo thisNode = nTopo.getNodeInfoByID(i);
            System.out.println(thisNode.getMyLocation().getX() + " "  +
                    thisNode.getMyLocation().getY() + " " + costEstimates[i]);
        }
        System.out.println("#-----------------------------");
    }
    
    private static void createNodeSpecificCodes(ATaGProgram aProgram,
            NetworkTopology nTopo, String dartRoot) {
        String ip = "";
        int count=0;
        for (int i=0;i < nTopo.getNodes().size();i++)
        {
            NodeInfo n = nTopo.getNodes().get(i);
            String type = (String)n.getAttributeByName("type");
            if(type.compareTo("freespot")!=0)
            {
                if(n.getAttributeByName("physicaladdress").toString().equalsIgnoreCase(NodeInfo.PHYSICAL_ADDR_IP_DYNAMIC))
                    continue;
                if(count!=0)               
                 ip+=","+"\""+n.getAttributeByName("physicaladdress")+"\"";
                else
                 ip+="\""+n.getAttributeByName("physicaladdress")+"\"";
                count++;
            }
        }
        
        
        String freespotCodeHeader = ""+
                "/*********************/\n"+
                "/** Startup.java */\n"+
                "/*********************/\n"+
                "package atag.apps.mainApp;\n"+
                "\n"+
                "import atag.runtime.platformDependent.*;\n"+
                "import java.io.IOException;\n"+
                "import java.util.Vector;\n"+
                "\n"+
                "import atag.common.*;\n"+
                "import atag.runtime.*;\n"+
                "import atag.runtime.ln.*;\n"+
                "import atag.runtime.ln.nodeAttributes.*;\n"+                
                "\n"+
                "import atag.apps.mainApp.gen.*;\n"+
                "\n"+
                "import com.sun.spot.util.Utils;\n"+
                "import javax.microedition.midlet.MIDlet;\n"+
                "import javax.microedition.midlet.MIDletStateChangeException;\n"+
                "\n"+
                "public class Startup extends MIDlet{\n"+
                "    \n"+
                "    private static int nextNodeId = 0;\n"+
                "    \n"+
                "    private static final int RANDOM_SEED = 12345;\n"+
                "    \n"+
                "    \n"+                
                "    private static String regionLabel;//My Region Label\n"+
                "    private static int regionID;//My Region ID\n"+
                "    private static float x;//My X Coordinate\n"+
                "    private static float y;//My Y Coordinate\n"+                   
                "    private static NodeInfo retNode=null;\n"+
                "    private static Vector attributes, assignedTasks;\n"+                    
                "    private static int id;//My ID\n"+               
                "    private static boolean hasGUITasks=false;// Host GUI tasks or not\n"+
                "    public static void createNode(NodeInfo info,\n"+
                "            ATaGProgram atagPrg){// throws NoSuchMethodException {\n"+
                "        \n"+
                "        int id = info.getMyId();\n"+
                "        \n"+
                "        // Create entities\n"+
                "        \n"+
                "        \n"+
                "        /*DatagramObjectIO objectIO = new DatagramObjectIO(\n"+
                "                LogicalNeighborhood.PORT, LogicalNeighborhood.BUFFER_SIZE,\n"+
                "                LogicalNeighborhood.RECEIVE_TIMEOUT);\n"+
                "        objectIO.start();\n"+
                "        Utils.sleep(1);*/\n"+
                "        \n"+
                "        \n"+
                "        final LogicalNeighborhoods ln = new LogicalNeighborhoods(adapterNodeInfotoNode(info));\n"+
                "        \n"+
                "        // START THE TICKS\n"+
                "        /*new Thread(new Runnable() {\n"+
                "            \n"+
                "            public void run() {\n"+
                "                ln.startUp(LogicalNeighborhood.LN_RUNOPTION_TICKSTART);\n"+
                "                Utils.sleep(1);\n"+
                "            }\n"+
                "        }).start();*/\n"+
                "        \n"+
                "        // MODIFIED BY LUCA - START THE QUEUE\n"+
                "        /*new Thread(new Runnable() {\n"+
                "            \n"+
                "            public void run() {\n"+
                "                ln.startUp(LogicalNeighborhood.LN_RUNOPTION_QUEUESTART);\n"+
                "                Utils.sleep(1);\n"+
                "            }\n"+
                "        }).start();*/\n"+
                "        \n"+
                "        \n"+
                "        AtagManager atagManager = new PreBuiltAtagManager();\n"+
                "        atagManager.setAtagProgram(atagPrg);\n"+
                "        atagManager.setNodeInfo(info);\n"+
                "        atagManager.setDataPool(new DataPool(ln, info, atagManager));\n"+
                "        atagManager.setUp();\n"+
                "        //start the ATaG Manager\n"+
                "        atagManager.start();\n"+
                "        \n"+
                "        \n"+
                "        \n"+
                "    }\n"+
                "    \n"+
                "     public static Node adapterNodeInfotoNode(NodeInfo info)\n"+
                "     {\n"+
                "         return new Node(info.getMyId(),info.getNodeAttributes(),info.getSendingCost());\n"+
                "     }\n\n"+
                "    public static void main(String[] args) {\n"+
                "        try {\n"+
                "            \n"+
                "            ATaGProgram atagPrg = returnMainApplication();\n"+
                "            atagPrg.sanitize();\n"+
                "            \n"+
                "            NodeInfo n = setUpNode();\n"+
                "            createNode(n,atagPrg);\n"+
                "            \n"+
                "            if(hasGUITasks)\n"+
                "               throw new RuntimeException();\n"+                
                "            \n"+                
                "        } catch (Exception e) {\n"+
                "            e.printStackTrace();\n"+
                "        }\n"+
                "    }\n"+
                "    \n"+
                "    \n"+
                "    public void run() throws IOException{\n"+
                "        try {\n"+
                "            \n"+
                "            ATaGProgram atagPrg = returnMainApplication();\n"+
                "            atagPrg.sanitize();\n"+
                "            \n"+
                "            NodeInfo n = setUpNode();\n"+
                "//                      NodeInfo n = setUpNode(0);\n"+
                "            createNode(n,atagPrg);\n"+
                "            \n"+
                "            if(hasGUITasks)\n"+
                "               throw new RuntimeException();\n"+                
                "            \n"+                
                "        } catch (Exception e) {\n"+
                "            e.printStackTrace();\n"+
                "        }\n"+
                "    }\n"+
                "    \n"+
                "    \n"+
                "    \n"+
                "    public static ATaGProgram returnMainApplication() {\n"+
                "        \n"+
                "        ATaGTaskDeclaration newTask;\n"+
                "        int[] tempFiringRule;\n"+
                "        int[] tempTaskLocation;\n"+
                "        \n"+
                "        ATaGProgram retProgram = new ATaGProgram();\n"+
                "        \n"+
                "        // set the tasks\n"+
                "        Vector tList = retProgram.getTaskList();\n"+
                "        \n";        
        for (ATaGTaskDeclaration at: aProgram.getTaskList()){
            
            // Handle External Tasks
            if(at.getFiringRule()[0] == ATaGTaskDeclaration.FIRING_EXTERN)
            {
                continue;
            }
            
            freespotCodeHeader += ""+
                    "        // "+at.getName()+"\n"+
                    "        newTask = new ATaGTaskDeclaration();\n"+
                    "        newTask.setName(\""+at.getName()+"\");\n"+
                    "        \n"+
                    "        tempFiringRule = new int[2];\n";
            int[] tempFiringRule = at.getFiringRule();
            freespotCodeHeader +=""+
                    "        tempFiringRule[0] = ATaGTaskDeclaration."+firingRuleToString(tempFiringRule[0])+";\n"+
                    "        tempFiringRule[1] = "+ tempFiringRule[1] +";\n"+
                    "        newTask.setFiringRule(tempFiringRule);\n"+
                    "        newTask.setRunAtInit("+(at.getRunAtInit()? "true": "false")+");\n"+
                    "        \n"+
                    "        tempTaskLocation = new int[2];\n";
            int[] tempLocation = at.getLocation();
            freespotCodeHeader+=""+
                    "        tempTaskLocation[0] = ATaGTaskDeclaration."+locationToString(tempLocation[0])+";\n"+
                    "        // set number of nodes per instance as the other element\n"+
                    "        tempTaskLocation[1] = "+tempLocation[1]+";\n"+
                    "        newTask.setLocation(tempTaskLocation);\n"+
                    "        newTask.setAt("+(at.getAt()? "true" : "false")+");\n"+
                    "        newTask.setSlash("+(at.getSlash()? "true":"false")+");\n"+
                    "        newTask.setMyRegionName(new String(\""+at.getMyRegionName()+"\"));\n";
            
            //TODO -- this supports only ONE attribute. The new String[] thing has only
            //one element. Make it a for loop
            if(at.getNeededAttribute() != null){
                freespotCodeHeader +=""+
                        "        newTask.setNeededAttribute(new StringSetAttribute(\""+at.getNeededAttribute().getKey()+"\",\n"+
                        "                new String[] { \""+(String)((HashSet)((SetAttribute)at.getNeededAttribute()).getValue()).toArray()[0]+"\" }));\n";
            }
            freespotCodeHeader +=""+
                    "        \n"+
                    "        tList.addElement(newTask);\n"+
                    "        \n"+
                    "        \n";
        }
        
        freespotCodeHeader+= ""+
                "        // now populate the data list\n"+
                "        Vector dList = retProgram.getDataList();\n"+
                "        ATaGDataItemDeclaration newDataItem;\n";
        
        for(ATaGDataItemDeclaration ad: aProgram.getDataList()){
            freespotCodeHeader+= ""+
                    "        newDataItem = new ATaGDataItemDeclaration();\n"+
                    "        newDataItem.setName(new String(\""+ad.getName()+"\"));\n"+
                    "        dList.addElement(newDataItem);\n"+
                    "        \n";
        }
        
        freespotCodeHeader+=""+
                "        \n"+
                "        // now populate the channel list\n"+
                "        Vector cList = retProgram.getChannelList();\n"+
                "        ScopedChannel newChannel;\n"+
                "        \n";
        
    for(ScopedChannel sc: aProgram.getChannelList()){
                
        // Handle External Tasks
            if(sc.isRPC())
            {
                continue;
            }
            freespotCodeHeader+=""+
                    "        newChannel = new ScopedChannel();\n"+
                    "        newChannel.setDataName(new String(\""+sc.getDataName()+"\"));\n"+
                    "        newChannel.setDirection(ScopedChannel."+channelTypeToString(sc.getDirection())+");\n"+
                    "        newChannel.setInterest(new String(\""+sc.getInterest()+":"+sc.getInterestParam();
            if(sc.getInterest().equalsIgnoreCase("region-hops")){
                freespotCodeHeader+= ":"+sc.getInterestLabel();
            }
            freespotCodeHeader+="\"));\n"+
                    "        newChannel.setLocalFlag("+(sc.isLocal() ? "true" : "false")+");\n"+
                    "        newChannel.setTaskName(new String(\""+sc.getTaskName()+"\"));\n"+
                    "        cList.addElement(newChannel);\n"+
                    "        \n";

    }
        
        freespotCodeHeader+=""+
                "        return retProgram;\n"+
                "    }\n"+
                "    \n";
        
        String freespotCodeTrailer = ""+
                "    \n"+
                "    protected void destroyApp(boolean b) throws MIDletStateChangeException {\n"+
                "    }\n"+
                "    \n"+
                "    protected void pauseApp() {\n"+
                "    }\n"+
                "    \n"+
                "    protected void startApp() throws MIDletStateChangeException {\n"+
                "        try {\n"+
                "            run();\n"+
                "        } catch (IOException ex) { //A problem in reading the sensors.\n"+
                "            ex.printStackTrace();\n"+
                "        }\n"+
                "    }\n"+
                "    \n"+
                "    \n"+
                "}\n";
        
       String androidCodeHeader = ""+
                "/*********************/\n"+
                "/** Startup.java */\n"+
                "/*********************/\n"+
                "package atag.apps.mainApp;\n"+
                "\n"+
                "import android.app.Service;\n"+
                "import android.content.Intent;\n"+
                "import android.os.Handler;\n"+
                "import android.os.IBinder;\n"+
                "import android.os.Message;\n"+
                "import android.os.Messenger;\n"+
                "import android.util.Log;\n"+
                "\n"+
                "import java.util.Vector;\n"+
                "\n"+
                "import atag.common.*;\n"+
                "import atag.runtime.*;\n"+
                "import atag.runtime.ln.*;\n"+
                "import atag.runtime.ln.nodeAttributes.*;\n"+
                "import atag.runtime.platformDependent.*;\n"+
                "\n"+
                "import atag.apps.mainApp.gen.*;\n"+
                "\n"+
                "public class Startup extends Service{\n"+
                "    \n"+
                "    private static int nextNodeId = 0;\n"+
                "    \n"+
                "    private static final int RANDOM_SEED = 12345;\n"+
                "    \n"+               
                "    private static String regionLabel;//My Region Label\n"+
                "    private static int regionID;//My Region ID\n"+
                "    private static float x;//My X Coordinate\n"+
                "    private static float y;//My Y Coordinate\n"+                   
                "    private static NodeInfo retNode=null;\n"+
                "    private static Vector attributes, assignedTasks;\n"+                    
                "    private static int id;//My ID\n"+
                "    private static boolean hasGUITasks=false;// Host GUI tasks or not\n"+                
                "\n"+                
                "    private NodeInfo n; \n"+
                "    \n"+
                "    public static void createNode(NodeInfo info,\n"+
                "            ATaGProgram atagPrg){// throws NoSuchMethodException {\n"+
                "        \n"+
                "        int id = info.getMyId();\n"+
                "        \n"+
                "        // Create entities\n"+
                "        \n"+
                "        \n"+
                "        /*DatagramObjectIO objectIO = new DatagramObjectIO(\n"+
                "                LogicalNeighborhood.PORT, LogicalNeighborhood.BUFFER_SIZE,\n"+
                "                LogicalNeighborhood.RECEIVE_TIMEOUT);\n"+
                "        objectIO.start();\n"+
                "        Utils.sleep(1);*/\n"+
                "        \n"+
                "        \n"+
                "        final LogicalNeighborhoods ln = new LogicalNeighborhoods(adapterNodeInfotoNode(info));\n"+
                "        \n"+
                "        \n"+
                "        AtagManager atagManager = new PreBuiltAtagManager();\n"+
                "        atagManager.setAtagProgram(atagPrg);\n"+
                "        atagManager.setNodeInfo(info);\n"+
                "        atagManager.setDataPool(new DataPool(ln, info, atagManager));\n"+
                "        atagManager.setUp();\n"+
                "        //start the ATaG Manager\n"+
                "        atagManager.start();\n"+
                "        \n"+
                "        \n"+
                "        \n"+
                "    }\n"+
                "    \n"+
                "     public static Node adapterNodeInfotoNode(NodeInfo info)\n"+
                "     {\n"+
                "         return new Node(info.getMyId(),info.getNodeAttributes(),info.getSendingCost());\n"+
                "     }\n\n"+
                "    \n"+
                "    \n"+
                "    \n"+
                "    public static ATaGProgram returnMainApplication() {\n"+
                "        \n"+
                "        ATaGTaskDeclaration newTask;\n"+
                "        int[] tempFiringRule;\n"+
                "        int[] tempTaskLocation;\n"+
                "        \n"+
                "        ATaGProgram retProgram = new ATaGProgram();\n"+
                "        \n"+
                "        // set the tasks\n"+
                "        Vector tList = retProgram.getTaskList();\n"+
                "        \n";
        for (ATaGTaskDeclaration at: aProgram.getTaskList()){
                        
            // Handle External Tasks
            if(at.getFiringRule()[0] == ATaGTaskDeclaration.FIRING_EXTERN)
            {
                continue;
            }
            
            
            androidCodeHeader += ""+
                    "        // "+at.getName()+"\n"+
                    "        newTask = new ATaGTaskDeclaration();\n"+
                    "        newTask.setName(\""+at.getName()+"\");\n"+
                    "        \n"+
                    "        tempFiringRule = new int[2];\n";
            int[] tempFiringRule = at.getFiringRule();
            androidCodeHeader +=""+
                    "        tempFiringRule[0] = ATaGTaskDeclaration."+firingRuleToString(tempFiringRule[0])+";\n"+
                    "        tempFiringRule[1] = "+ tempFiringRule[1] +";\n"+
                    "        newTask.setFiringRule(tempFiringRule);\n"+
                    "        newTask.setRunAtInit("+(at.getRunAtInit()? "true": "false")+");\n"+
                    "        \n"+
                    "        tempTaskLocation = new int[2];\n";
            int[] tempLocation = at.getLocation();
            androidCodeHeader+=""+
                    "        tempTaskLocation[0] = ATaGTaskDeclaration."+locationToString(tempLocation[0])+";\n"+
                    "        // set number of nodes per instance as the other element\n"+
                    "        tempTaskLocation[1] = "+tempLocation[1]+";\n"+
                    "        newTask.setLocation(tempTaskLocation);\n"+
                    "        newTask.setAt("+(at.getAt()? "true" : "false")+");\n"+
                    "        newTask.setSlash("+(at.getSlash()? "true":"false")+");\n"+
                    "        newTask.setMyRegionName(new String(\""+at.getMyRegionName()+"\"));\n";

            //TODO -- this supports only ONE attribute. The new String[] thing has only
            //one element. Make it a for loop
            if(at.getNeededAttribute() != null){
                androidCodeHeader +=""+
                        "        newTask.setNeededAttribute(new StringSetAttribute(\""+at.getNeededAttribute().getKey()+"\",\n"+
                        "                new String[] { \""+(String)((HashSet)((SetAttribute)at.getNeededAttribute()).getValue()).toArray()[0]+"\" }));\n";
            }
            androidCodeHeader +=""+
                    "        \n"+
                    "        tList.addElement(newTask);\n"+
                    "        \n"+
                    "        \n";
        }

        androidCodeHeader+= ""+
                "        // now populate the data list\n"+
                "        Vector dList = retProgram.getDataList();\n"+
                "        ATaGDataItemDeclaration newDataItem;\n";

        for(ATaGDataItemDeclaration ad: aProgram.getDataList()){
            androidCodeHeader+= ""+
                    "        newDataItem = new ATaGDataItemDeclaration();\n"+
                    "        newDataItem.setName(new String(\""+ad.getName()+"\"));\n"+
                    "        dList.addElement(newDataItem);\n"+
                    "        \n";
        }

        androidCodeHeader+=""+
                "        \n"+
                "        // now populate the channel list\n"+
                "        Vector cList = retProgram.getChannelList();\n"+
                "        ScopedChannel newChannel;\n"+
                "        \n";

        for(ScopedChannel sc: aProgram.getChannelList()){
            
            // Handle External Tasks
            if(sc.isRPC())
            {
                continue;
            }
            androidCodeHeader+=""+
                    "        newChannel = new ScopedChannel();\n"+
                    "        newChannel.setDataName(new String(\""+sc.getDataName()+"\"));\n"+
                    "        newChannel.setDirection(ScopedChannel."+channelTypeToString(sc.getDirection())+");\n"+
                    "        newChannel.setInterest(new String(\""+sc.getInterest()+":"+sc.getInterestParam();
            if(sc.getInterest().equalsIgnoreCase("region-hops")){
                androidCodeHeader+= ":"+sc.getInterestLabel();
            }
            androidCodeHeader+="\"));\n"+
                    "        newChannel.setLocalFlag("+(sc.isLocal() ? "true" : "false")+");\n"+
                    "        newChannel.setTaskName(new String(\""+sc.getTaskName()+"\"));\n"+
                    "        cList.addElement(newChannel);\n"+
                    "        \n";

        }

        androidCodeHeader+=""+
                "        return retProgram;\n"+
                "    }\n"+
                "    \n";

        String androidCodeTrailer = ""+
                "    \n"+                
                "    \n"+
                "   final Messenger messenger = new Messenger(new IncomingHandler()); \n"+   
   
                "    class IncomingHandler extends Handler { // Handler of incoming messages from clients.\n"+
                "        @Override\n"+
                "        public void handleMessage(Message msg) {\n"+
    	        "            n.setRegionAttribute(Integer.parseInt((String) msg.obj));\n"+
    	        "             System.out.println(\"Region ID set to \" + msg.obj);\n"+
                "        }\n"+
                "    }\n"+
                "    \n"+
                "   @Override\n"+
                "   public void onCreate() { \n"+
		"       super.onCreate(); \n"+
                "       Log.i(\"Info:\", \"Service started\"); \n"+
		"       try { \n\n"+
		"           ATaGProgram atagPrg = returnMainApplication(); \n"+
		"           atagPrg.sanitize(); \n\n"+

		"           n = setUpNode(); \n"+
		"           createNode(n, atagPrg); \n"+
                " \n"+
		"           } catch (Exception e) { \n"+
		"           Log.e(\"Exception during startup\", e.getMessage(), e); \n"+
		"           } \n"+
                "   } \n"+
                "   \n"+
                "   @Override \n"+
                "   public IBinder onBind(Intent arg0) { \n"+
		"       return messenger.getBinder(); \n"+
                "   } \n"+
                "}\n";

        String j2seAndSpothostCodeHeader = ""+
                "/*********************/\n"+
                "/** Startup.java */\n"+
                "/*********************/\n"+
                "package atag.apps.mainApp;\n"+
                "\n"+
                "import atag.runtime.platformDependent.*;\n"+
                "import java.io.IOException;\n"+
                "import java.util.Vector;\n"+
                "\n"+
                "import atag.common.*;\n"+
                "import atag.runtime.*;\n"+
                "import atag.runtime.ln.*;\n"+
                "import atag.runtime.ln.nodeAttributes.*;\n"+                
                "\n"+
                "import atag.apps.mainApp.gen.*;\n"+
                "\n"+
                "public class Startup {\n"+
                "    \n"+
                "    private static int nextNodeId = 0;\n"+
                "    \n"+
                "    private static final int RANDOM_SEED = 12345;\n"+
                "    \n"+
                "    \n"+                
                "    private static String regionLabel;//My Region Label\n"+
                "    private static int regionID;//My Region ID\n"+
                "    private static float x;//My X Coordinate\n"+
                "    private static float y;//My Y Coordinate\n"+                   
                "    private static NodeInfo retNode=null;\n"+
                "    private static Vector attributes, assignedTasks;\n"+                    
                "    private static int id;//My ID\n"+               
                "    private static boolean hasGUITasks=false;// Host GUI tasks or not\n"+
                "    public static void createNode(NodeInfo info,\n"+
                "            ATaGProgram atagPrg){// throws NoSuchMethodException {\n"+
                "        \n"+
                "        int id = info.getMyId();\n"+
                "        \n"+
                "        // Create entities\n"+
                "        \n"+
                "        \n"+
                "        /*DatagramObjectIO objectIO = new DatagramObjectIO(\n"+
                "                LogicalNeighborhood.PORT, LogicalNeighborhood.BUFFER_SIZE,\n"+
                "                LogicalNeighborhood.RECEIVE_TIMEOUT);\n"+
                "        objectIO.start();\n"+
                "        Utils.sleep(1);*/\n"+
                "        \n"+
                "        \n"+
                "        final LogicalNeighborhoods ln = new LogicalNeighborhoods(adapterNodeInfotoNode(info));\n"+
                "        \n"+
                "        // START THE TICKS\n"+
                "        /*new Thread(new Runnable() {\n"+
                "            \n"+
                "            public void run() {\n"+
                "                ln.startUp(LogicalNeighborhood.LN_RUNOPTION_TICKSTART);\n"+
                "                Utils.sleep(1);\n"+
                "            }\n"+
                "        }).start();*/\n"+
                "        \n"+
                "        // MODIFIED BY LUCA - START THE QUEUE\n"+
                "        /*new Thread(new Runnable() {\n"+
                "            \n"+
                "            public void run() {\n"+
                "                ln.startUp(LogicalNeighborhood.LN_RUNOPTION_QUEUESTART);\n"+
                "                Utils.sleep(1);\n"+
                "            }\n"+
                "        }).start();*/\n"+
                "        \n"+
                "        \n"+
                "        AtagManager atagManager = new PreBuiltAtagManager();\n"+
                "        atagManager.setAtagProgram(atagPrg);\n"+
                "        atagManager.setNodeInfo(info);\n"+
                "        atagManager.setDataPool(new DataPool(ln, info, atagManager));\n"+
                "        atagManager.setUp();\n"+
                "        //start the ATaG Manager\n"+
                "        atagManager.start();\n"+
                "        \n"+
                "        \n"+
                "        \n"+
                "    }\n"+
                "    \n"+
                "     public static Node adapterNodeInfotoNode(NodeInfo info)\n"+
                "     {\n"+
                "         return new Node(info.getMyId(),info.getNodeAttributes(),info.getSendingCost());\n"+
                "     }\n\n"+
                "    public static void main(String[] args) {\n"+
                "        try {\n"+
                "            \n"+
                "            ATaGProgram atagPrg = returnMainApplication();\n"+
                "            atagPrg.sanitize();\n"+
                "            \n"+
                "            NodeInfo n = setUpNode();\n"+
                "            createNode(n,atagPrg);\n"+
                "            \n"+
                "            if(hasGUITasks)\n"+
                "               atag.apps.mainApp.gui.GUILauncher.launchGUI();\n"+                
                "            \n"+                
                "        } catch (Exception e) {\n"+
                "            e.printStackTrace();\n"+
                "        }\n"+
                "    }\n"+
                "    \n"+
                "    \n"+
                "    public static ATaGProgram returnMainApplication() {\n"+
                "        \n"+
                "        ATaGTaskDeclaration newTask;\n"+
                "        int[] tempFiringRule;\n"+
                "        int[] tempTaskLocation;\n"+
                "        \n"+
                "        ATaGProgram retProgram = new ATaGProgram();\n"+
                "        \n"+
                "        // set the tasks\n"+
                "        Vector tList = retProgram.getTaskList();\n"+
                "        \n";        
        for (ATaGTaskDeclaration at: aProgram.getTaskList()){
            
            // Handle External Tasks
            if(at.getFiringRule()[0] == ATaGTaskDeclaration.FIRING_EXTERN)
            {
                continue;
            }
            
            j2seAndSpothostCodeHeader += ""+
                    "        // "+at.getName()+"\n"+
                    "        newTask = new ATaGTaskDeclaration();\n"+
                    "        newTask.setName(\""+at.getName()+"\");\n"+
                    "        \n"+
                    "        tempFiringRule = new int[2];\n";
            int[] tempFiringRule = at.getFiringRule();
            j2seAndSpothostCodeHeader +=""+
                    "        tempFiringRule[0] = ATaGTaskDeclaration."+firingRuleToString(tempFiringRule[0])+";\n"+
                    "        tempFiringRule[1] = "+ tempFiringRule[1] +";\n"+
                    "        newTask.setFiringRule(tempFiringRule);\n"+
                    "        newTask.setRunAtInit("+(at.getRunAtInit()? "true": "false")+");\n"+
                    "        \n"+
                    "        tempTaskLocation = new int[2];\n";
            int[] tempLocation = at.getLocation();
            j2seAndSpothostCodeHeader+=""+
                    "        tempTaskLocation[0] = ATaGTaskDeclaration."+locationToString(tempLocation[0])+";\n"+
                    "        // set number of nodes per instance as the other element\n"+
                    "        tempTaskLocation[1] = "+tempLocation[1]+";\n"+
                    "        newTask.setLocation(tempTaskLocation);\n"+
                    "        newTask.setAt("+(at.getAt()? "true" : "false")+");\n"+
                    "        newTask.setSlash("+(at.getSlash()? "true":"false")+");\n"+
                    "        newTask.setMyRegionName(new String(\""+at.getMyRegionName()+"\"));\n";
            
            //TODO -- this supports only ONE attribute. The new String[] thing has only
            //one element. Make it a for loop
            if(at.getNeededAttribute() != null){
                j2seAndSpothostCodeHeader +=""+
                        "        newTask.setNeededAttribute(new StringSetAttribute(\""+at.getNeededAttribute().getKey()+"\",\n"+
                        "                new String[] { \""+(String)((HashSet)((SetAttribute)at.getNeededAttribute()).getValue()).toArray()[0]+"\" }));\n";
            }
            j2seAndSpothostCodeHeader +=""+
                    "        \n"+
                    "        tList.addElement(newTask);\n"+
                    "        \n"+
                    "        \n";
        }
        
        j2seAndSpothostCodeHeader+= ""+
                "        // now populate the data list\n"+
                "        Vector dList = retProgram.getDataList();\n"+
                "        ATaGDataItemDeclaration newDataItem;\n";
        
        for(ATaGDataItemDeclaration ad: aProgram.getDataList()){
            j2seAndSpothostCodeHeader+= ""+
                    "        newDataItem = new ATaGDataItemDeclaration();\n"+
                    "        newDataItem.setName(new String(\""+ad.getName()+"\"));\n"+
                    "        dList.addElement(newDataItem);\n"+
                    "        \n";
        }
        
        j2seAndSpothostCodeHeader+=""+
                "        \n"+
                "        // now populate the channel list\n"+
                "        Vector cList = retProgram.getChannelList();\n"+
                "        ScopedChannel newChannel;\n"+
                "        \n";
        
    for(ScopedChannel sc: aProgram.getChannelList()){
                
        // Handle External Tasks
            if(sc.isRPC())
            {
                continue;
            }
            j2seAndSpothostCodeHeader+=""+
                    "        newChannel = new ScopedChannel();\n"+
                    "        newChannel.setDataName(new String(\""+sc.getDataName()+"\"));\n"+
                    "        newChannel.setDirection(ScopedChannel."+channelTypeToString(sc.getDirection())+");\n"+
                    "        newChannel.setInterest(new String(\""+sc.getInterest()+":"+sc.getInterestParam();
            if(sc.getInterest().equalsIgnoreCase("region-hops")){
                j2seAndSpothostCodeHeader+= ":"+sc.getInterestLabel();
            }
            j2seAndSpothostCodeHeader+="\"));\n"+
                    "        newChannel.setLocalFlag("+(sc.isLocal() ? "true" : "false")+");\n"+
                    "        newChannel.setTaskName(new String(\""+sc.getTaskName()+"\"));\n"+
                    "        cList.addElement(newChannel);\n"+
                    "        \n";

    }
        
        j2seAndSpothostCodeHeader+=""+
                "        return retProgram;\n"+
                "    }\n"+
                "    \n";
        
        String j2seAndSpothostCodeTrailer = ""+
                "    \n"+
                "}\n";

        
        for(NodeInfo ni: nTopo.getNodes()){
            //for each node, create the files.
            boolean hasGUITasks=false;
            ArrayList<String> GUITasks=new ArrayList<String>();
            String nodeSpecificCode = ""+                    
                    "    /**\n"+
                    "     * Node-per-node setup.\n"+
                    "     */\n"+
                    "    private static NodeInfo setUpNode() {\n"+
                    "        id = "+ni.getMyId()+"; // \n"+
                    "        regionLabel = \""+ni.getRegionLabel()+"\"; // \n"+                    
                    "        regionID = "+ni.getAttributeByName(ni.getRegionLabel())+";\n"+
                    "        x = (float)"+ni.getMyLocation().getX()+";\n"+
                    "        y = (float)"+ni.getMyLocation().getY()+";\n"+
                    "        \n"+
                    "        \n"+
                    "        // Creating the node\n"+
                    "        attributes = new Vector();\n"+
                    "        attributes.addElement(new IntegerAttribute(\""+NodeInfo.NODE_ID_ATTR_NAME+"\", id));\n"+                    
                    "        attributes.addElement(new IntegerAttribute(\""+ni.getRegionLabel()+"\", regionID));\n"+
                    "        String ip[]={"+ip+"};\n"+
                    "        attributes.addElement(new StringSetAttribute(\"ip\",ip));\n"+
                    "        assignedTasks = new Vector();\n";
            System.out.println("reg lab"+ni.getRegionLabel());
            //place tasks
            for(ATaGTaskDeclaration at: aProgram.getTaskList()){
                if(ni.isTaskAssigned(at.getID())){

                    NodeAttribute neededAttr = at.getNeededAttribute();
                    // Check ability
                     if(neededAttr!=null)
                      {
                        Set s=(Set) neededAttr.getValue();
                        for(Object x:s)
                        {
                            // Checking each object inside the values set to see if this is a GUI Task
                            if(x instanceof String && "GUI".equalsIgnoreCase((String) x))
                            {
                                hasGUITasks=true;
                                GUITasks.add(at.getName());
                                break;
                            }
                        }
                       }
                    if(hasGUITasks==true)
                    {
                        nodeSpecificCode+= ""+
                                "        hasGUITasks=true;\n";
                    }
                    nodeSpecificCode += ""+
                            "        System.out.println(\"Placing "+at.getName()+" on node id \"\n"+
                            "                + id + \" in Floor \" + regionID + \" at \" + x + \",\" + y);\n"+
                            "        assignedTasks.addElement(String.valueOf(IDConstants.T_"+at.getName().toUpperCase()+"));\n"+
                            "        \n";
                }
            }
            
            //TODO - make this better. The string based approach is no good
            nodeSpecificCode += ""+
                    "		// get the ability Label\n"+                    
                    "		String abilityString = \""+ni.getAbilityString()+"\";\n"+
                    "		if (!(abilityString.equalsIgnoreCase(\"none\"))) {\n"+
                    "               attributes.addElement(new StringSetAttribute(ATaGTaskDeclaration.ABILITY_ATTRIBUTE_NAME, \n"+
                    "                                       StringHelper.splitString(abilityString, \',\')));\n"+                
                    "           }\n"+
                    "		\n";
            
            nodeSpecificCode += ""+
                    "        retNode =  new NodeInfo(id,\n"+
                    "                new NodeLocation(x, y), attributes, 1, assignedTasks,\n"+
                    "                new SunSPOTClock());\n"+
                    "        \n"+
                    "        retNode.setRegionLabel(\""+ni.getRegionLabel()+"\");\n"+
                    "        retNode.setAbilityString(\""+ni.getAbilityString()+"\");\n"+
                    "        return retNode;\n"+
                    "        \n"+
                    "    }\n";
            // TODO Should use approch similar to that used for android so that
            // unwanted code is not generated.
            String nodeCode;
            if( ((String)ni.getAttributeByName("type")).compareTo("android")==0 )
            {
                nodeCode = ""+
                    "/**** Code for Node "+ ni.getMyId()+" ********/\n"+
                    androidCodeHeader+
                    nodeSpecificCode+
                    androidCodeTrailer;
            }
            else if ( ((String)ni.getAttributeByName("type")).compareTo("hostspot")==0 ||
                    ((String)ni.getAttributeByName("type")).compareTo("j2se")==0 )
            {
                nodeCode = ""+
                "/**** Code for Node "+ ni.getMyId()+" ********/\n"+
                j2seAndSpothostCodeHeader+
                nodeSpecificCode+
                j2seAndSpothostCodeTrailer;                                                                   
            }
            else 
            {
                nodeCode = ""+
                    "/**** Code for Node "+ ni.getMyId()+" ********/\n"+
                    freespotCodeHeader+
                    nodeSpecificCode+
                    freespotCodeTrailer;
            }
            //System.out.print(nodeCode);
            
            //recursively copy the base files
            
            File sourceDirforspot = new File(dartRoot+File.separator+"app-template-freespot");
            File sourceDirforhostspot = new File(dartRoot+File.separator+"app-template-hostspot");
            File sourceDirforj2se = new File(dartRoot+File.separator+"app-template-j2se");
            File sourceDirforandroid = new File(dartRoot+File.separator+"app-template-android");
            File destDir = new File(dartRoot+File.separator + "node" + ni.getMyId());
            destDir.mkdirs();
            try {
                if ( ((String)ni.getAttributeByName("type")).compareTo("freespot")==0)
                     Helper.recursivelyCopyDirectory(sourceDirforspot, destDir);
                else if ( ((String)ni.getAttributeByName("type")).compareTo("hostspot")==0)
                     Helper.recursivelyCopyDirectory(sourceDirforhostspot, destDir);
                else if ( ((String)ni.getAttributeByName("type")).compareTo("j2se")==0)
                    Helper.recursivelyCopyDirectory(sourceDirforj2se, destDir);
                else if ( ((String)ni.getAttributeByName("type")).compareTo("android")==0)
                    Helper.recursivelyCopyDirectory(sourceDirforandroid, destDir);
                } catch (IOException ex) {
                System.err.println("Recursive copying failed");
                ex.printStackTrace();
            }
            
            //create Startup.java in atag.apps.mainApp
            try {
                BufferedWriter startup = new BufferedWriter(new FileWriter(
                        destDir.getAbsolutePath() + File.separator + "src" +
                        File.separator + "atag" + File.separator + "apps" +
                        File.separator + "mainApp" +
                        File.separator+ "Startup.java"));
                startup.write(nodeCode);
                startup.close();
            } catch (IOException ex) {
                System.err.println("Could not write " +
                        destDir.getAbsolutePath() + File.separator + "src" +
                        File.separator + "atag" + File.separator + "apps" +
                        File.separator + "mainApp" +
                        File.separator+ "Startup.java");
                System.err.println(ex.getMessage());
            }           
            String startupActivityCode="";
            String startupActivityHeader=""+
               "package atag.apps.mainApp; \n"+
               " \n"+
               "import android.app.Activity; \n"+
               "import android.content.Context; \n"+
               "import android.content.Intent; \n"+
               "import android.os.Bundle; \n"+
               "import android.os.IBinder; \n"+
               "import android.os.Message; \n"+
               "import android.os.Messenger; \n"+
               "import android.view.Menu; \n"+
               "import android.view.MenuInflater; \n"+
               "import android.view.MenuItem; \n"+
               "import android.content.ServiceConnection; \n"+               
               "import android.content.ComponentName; \n"+
               "import android.widget.Toast; \n"+
               " \n"+
               "import static atag.runtime.NodeInfo.REGION_ID_INVALID; \n"+                  
               " \n";
            
            String startupActivityRegionUpdateCode=""+
	       "    /* \n"+
	       "    * Creates options menu. \n"+
	       "    *  \n"+
	       "     * @param menu the Menu to be populated \n"+
	       "     */ \n"+
	       "    @Override \n"+
	       "    public boolean onCreateOptionsMenu(Menu menu) { \n"+
	       "       MenuInflater inflater = getMenuInflater(); \n"+
	       "       inflater.inflate(R.menu.main_menu, menu); \n"+
	       "       return true; \n"+
	       "    } \n"+
               "     \n"+
               "     \n"+   
	       "    /* \n"+
	       "     * Handles menu item selections \n"+
	       "     *  \n"+
	       "     * @param item the selected MenuItem \n"+
	       "     */ \n"+
	       "    @Override \n"+
	       "    public boolean onOptionsItemSelected(MenuItem item) { \n"+
               " \n"+     
	       "    switch (item.getItemId()) { \n"+
	       "        case R.id.location: \n"+
	       "            Intent i=new Intent(ACTION_GET_LOCATION); \n"+
	       "            startActivityForResult(i, GET_LOCATION); \n"+
	       "            //IntentIntegrator.initiateScan(this); \n"+			
	       "            return true; \n"+
	       "        case R.id.exit: \n"+
	       "            moveTaskToBack(true); \n"+
	       "            return true; \n"+
	       "        } \n"+
	       "        return false; \n"+
               "    } \n"+
               " \n"+
	       "    private ServiceConnection mConnection = new ServiceConnection() {  \n"+
               " \n"+
	       "        public void onServiceConnected(ComponentName className, IBinder service) { \n"+
               "            Messenger messenger = new Messenger(service); \n"+
	       "            try { \n"+
               "                Message msg = Message.obtain(); \n"+
	       "                msg.obj = m_regionID + \"\"; \n"+
	       "                messenger.send(msg); \n"+                    
               "                unbindService(mConnection); \n"+
	       "            } catch (Exception e) { \n"+
	       "                e.printStackTrace(); \n"+
	       "            } \n"+
	       "        } \n"+

	       "        public void onServiceDisconnected(ComponentName className) { \n"+
               "            // This is called when the connection with the service has been \n"+
               "            // unexpectedly disconnected - process crashed. \n"+
               "            System.out.println(\"Disconnected from SERVICE \"); \n"+
               "	} \n"+
               "    }; \n"+
               " \n"+
               "    public void onActivityResult(int requestCode, int resultCode, Intent intent) { \n"+
               "        Context context = getApplicationContext(); \n"+
               "        int duration = Toast.LENGTH_SHORT; \n"+
               "        CharSequence text; \n"+
               "        if ( (requestCode == GET_LOCATION) && (resultCode == RESULT_OK) ) { \n"+
               "            int location = intent.getIntExtra(\"location\", DEFAULT_LOCATION); \n"+
               "            if (location != DEFAULT_LOCATION) { \n"+
               "		m_regionID=location; \n"+
               "		bindService(new Intent(this, Startup.class), mConnection, \n"+
               "		Context.BIND_AUTO_CREATE); \n"+
               "                if (m_regionID == REGION_ID_INVALID) \n"+
               "                    text = \"Moved to INVALID Region\"; \n"+
               "                else \n"+
               "                    text = \"Moved to Region ID: \" + m_regionID; \n"+
               "		Toast toast = Toast.makeText(context, text, duration); \n"+
               "                toast.show(); \n"+
               "                return; \n"+
               "            } \n"+
               "        } \n"+
               "        text = \"Unable to obtain location. Location not changed.\"; \n"+
               "        Toast toast = Toast.makeText(context, text, duration); \n"+
               "        toast.show(); \n"+
               "    } \n"+
               " \n"+
               "    private static final int GET_LOCATION = 1; \n"+
               "    private static final int DEFAULT_LOCATION = -2; \n"+
               "    private static final String ACTION_GET_LOCATION = \"atag.ACTION_GET_LOCATION\"; \n"+                     
               "    private int m_regionID=DEFAULT_LOCATION;\n"+
               "\n";
                    
            if(hasGUITasks)
            {
              startupActivityCode=startupActivityHeader+               
               "import android.app.ListActivity; \n"+
               "import android.view.View; \n"+
               "import android.widget.ArrayAdapter; \n"+
               "import android.widget.ListView; \n"+
               "import atag.apps.mainApp.gui.*; \n"+                
               " \n"+
               "public class StartupActivity extends ListActivity { \n"+
               "     /** Called when the activity is first created. */ \n"+
               "    @Override \n"+
               "    public void onCreate(Bundle savedInstanceState) { \n"+
               "        super.onCreate(savedInstanceState); \n"+
               "        \n"+
               "        Context c = getBaseContext(); \n"+
               "        Intent i = new Intent(c, Startup.class); \n"+
               "        c.startService(i); \n"+
	       "        setListAdapter(new ArrayAdapter<String>(this, \n"+
               "                	android.R.layout.simple_list_item_1, GUI_TASK_LABELS)); \n"+
               "        ListView l = getListView(); \n"+
               "        l.setTextFilterEnabled(true); \n"+
               "        l.setChoiceMode(ListView.CHOICE_MODE_SINGLE); \n"+
               "    } \n"+
               " \n"+
               "    @Override \n"+
               "   public void onListItemClick(ListView parent, View v, int position, long id) { \n"+
               "        Intent intent = new Intent(this, GUI_TASK_CLASSES[position]); \n"+
               "        startActivity(intent); \n"+               
               "   } \n"+                             
               " \n"+
               startupActivityRegionUpdateCode;
              // TO DO Figure out a better way to create the list.
               startupActivityCode+="   static final String[] GUI_TASK_LABELS = new String[] { \n";
               boolean first=true;
               for(String x:GUITasks)
               {
                   if(first)
                   {
                       startupActivityCode+="       \""+x+"\""+"\n";
                       first=false;
                   }
                   else
                   {
                    startupActivityCode+="      ,\""+x+"\""+"\n";
                   }
               }
               startupActivityCode+="   };\n";
               startupActivityCode+="   static final Class[] GUI_TASK_CLASSES = new Class[] { \n";
               first=true;
               for(String x:GUITasks)
               {
                   if(first)
                   {
                       startupActivityCode+="       "+x+"GUI.class"+"\n";
                       first=false;
                   }
                   else
                   {
                       startupActivityCode+="       ,"+x+"GUI.class"+"\n";
                   }
               }
               startupActivityCode+="   };\n";
               startupActivityCode+="} \n";
            }
            else
            {
              startupActivityCode=startupActivityHeader+               
               "public class StartupActivity extends Activity { \n"+
               "    /** Called when the activity is first created. */ \n"+
               "    @Override \n"+
               "    public void onCreate(Bundle savedInstanceState) { \n"+
               "        super.onCreate(savedInstanceState); \n"+
               " \n"+
               "		Context c = getBaseContext(); \n"+
               "                Intent i = new Intent(c, Startup.class); \n"+
               "                c.startService(i); \n"+
               "		// Add code for the GUI of the launching activity \n"+
               "                // or call finish() if you do not need a GUI \n"+
               "    } \n"+    
               " \n"+
               startupActivityRegionUpdateCode+       
               "} \n";
            }
            if ( ((String)ni.getAttributeByName("type")).compareTo("android")==0)
            {
                //create StartupActivity.java in atag.apps.mainApp for android
                try {
                    BufferedWriter startup = new BufferedWriter(new FileWriter(
                        destDir.getAbsolutePath() + File.separator + "src" +
                        File.separator + "atag" + File.separator + "apps" +
                        File.separator + "mainApp" +
                        File.separator+ "StartupActivity.java"));
                    startup.write(startupActivityCode);
                    startup.close();
                } catch (IOException ex) {
                    System.err.println("Could not write " +
                            destDir.getAbsolutePath() + File.separator + "src" +
                            File.separator + "atag" + File.separator + "apps" +
                            File.separator + "mainApp" +
                            File.separator+ "StartupActivity.java");
                    System.err.println(ex.getMessage());
                }
            }
           }
        
    }
    
    private static String firingRuleToString(int i) {
        switch(i){
            case ATaGTaskDeclaration.FIRING_PERIODIC:
                return "FIRING_PERIODIC";
            case ATaGTaskDeclaration.FIRING_ANYDATA:
                return "FIRING_ANYDATA";
            case ATaGTaskDeclaration.FIRING_ALLDATA:
                return "FIRING_ALLDATA";
            case ATaGTaskDeclaration.FIRING_TRIGGERED:
                return "FIRING_TRIGGERED";

            default:
                return null;
        }
    }
    
    private static String locationToString(int i) {
        switch (i){
            case ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE:
                return "INSTANTIATION_NODES_PER_INSTANCE";
            case ATaGTaskDeclaration.INSTANTIATION_NODES_PER_INSTANCE_FRACTIONAL:
                return "INSTANTIATION_NODES_PER_INSTANCE_FRACTIONAL";
            case ATaGTaskDeclaration.INSTANTIATION_ONE_ANYWHERE:
                return "INSTANTIATION_ONE_ANYWHERE";
            case ATaGTaskDeclaration.INSTANTIATION_ONE_ON_NODE_ID:
                return "INSTANTIATION_ONE_ON_NODE_ID";
            case ATaGTaskDeclaration.INSTANTIATION_PARTITION_PER_INSTANCE:
                return "INSTANTIATION_PARTITION_PER_INSTANCE";
            default:
                return null;
        }
    }
    
    private static String channelTypeToString(int i) {
        switch(i){
            case ScopedChannel.CHANNEL_TYPE_INPUT:
                return "CHANNEL_TYPE_INPUT";
            case ScopedChannel.CHANNEL_TYPE_OUTPUT:
                return "CHANNEL_TYPE_OUTPUT";
            case ScopedChannel.CHANNEL_TYPE_REQUEST_RESPONSE:
                return "CHANNEL_TYPE_REQUEST_RESPONSE";

            default:
                return null;
        }
    }
    
}